////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef stream_h__
#define stream_h__

#include "core/types.h"
#include "iosystem/uri.h"
#include "iosystem/mime.h"
#include "core/referencecount.h"
#include "threading/criticalsection.h"

namespace IO
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	Stream
	///
	/// \brief	This class provides an abstract interface for every read-write-access of
	///			any sequence of bytes.
	///			This should be used as a base class for all classes that needs an read-write
	///			interface for accessing its data. Just as some examples for this the engine 
	///			provides types for read and write binary, xml, zips, 7zips and text data types.
	///			If necessary there could easily be added more different classes.
	///
	///			Thanks to the 
	///
	/// \author	Khaos
	/// \date	26.12.2009
	////////////////////////////////////////////////////////////////////////////////////////////////////
	class Stream : public Core::ReferenceCount
	{
		RE_DeclareClass(Stream);

	public:


		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \enum	AccessMode
		///
		/// \brief	Values that represent AccessMode. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		enum AccessMode
		{
			ReadAccess			= 0	,
			WriteAccess				,
			AppendAccess			,
			ReadWriteAccess
		};

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \enum	AccessPattern
		///
		/// \brief	Values that represent AccessPattern. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		enum AccessPattern
		{
			Random				= 0	,
			Sequential
		};

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \enum	SeekOrigin
		///
		/// \brief	Values that represent SeekOrigin. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		enum SeekOrigin
		{
			Begin				= 0	,
			Current					,
			End
		};

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	Stream()
		///
		/// \brief	Default constructor. 
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Stream();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual ~Stream()
		///
		/// \brief	Finaliser. 
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual ~Stream();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool Open()
		///
		/// \brief	Opens the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	true if it succeeds, false if it fails. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool Open();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Close()
		///
		/// \brief	Closes the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Close();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsOpen() const
		///
		/// \brief	Returns true if the stream is open.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	true if open, false if not. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsOpen() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool CanRead() const
		///
		/// \brief	Returns true if the stream supports reading.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	True if the stream supports reading, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool CanRead() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool CanWrite() const
		///
		/// \brief	Returns true if the stream supports writing.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	True if the stream supports writing, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool CanWrite() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool CanSeek() const
		///
		/// \brief	Returns true if the stream supports seeking.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	True if the stream supports seeking, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool CanSeek() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool CanMap() const
		///
		/// \brief	Returns true if the stream supports direct memory access.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	True if the stream supports direct memory access, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool CanMap() const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetURI(const URI & uri)
		///
		/// \brief	Sets the stream location as URI. The URI identifies the source resource
		///			of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	uri	The uri. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetURI(const URI & uri);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void SetSize(Size size)
		///
		/// \brief	This will set a new size for the stream.
		///			Remember when you set a new size smaller then the previous on the existing
		///			contents of the stream will be clipped.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	size	The size. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void SetSize(int size);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void SetPosition(Position pos)
		///
		/// \brief	Sets the position of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	pos	The position. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void SetPosition(int pos);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetAccessMode(AccessMode mode)
		///
		/// \brief	Sets the intended access mode of the stream. 
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	mode	The mode. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetAccessMode(AccessMode mode);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetAccessPattern(AccessPattern pattern)
		///
		/// \brief	Sets the access pattern of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	pattern	The pattern. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetAccessPattern(AccessPattern pattern);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void SetMediaType(const MIME & mime)
		///
		/// \brief	Sets the media type of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	mime	The mime. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetMediaType(const MIME & mime);




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	const URI & GetURI() const
		///
		/// \brief	Returns the URI.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	The uri. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		const URI & GetURI() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual int GetSize() const
		///
		/// \brief	Returns the size of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	The size. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual int GetSize() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual Position GetPosition() const
		///
		/// \brief	Returns the position within the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	The position. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual int GetPosition() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	AccessMode GetAccessMode() const
		///
		/// \brief	Returns the access mode of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	The access mode. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		AccessMode GetAccessMode() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	AccessPattern GetAccessPattern() const
		///
		/// \brief	Returns the access pattern of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	The access pattern. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		AccessPattern GetAccessPattern() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	const MIME & GetMediaType() const
		///
		/// \brief	Returns the media type of the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	The media type. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		const MIME & GetMediaType() const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Write(const void * ptr, Size bytes)
		///
		/// \brief	Writes to the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	ptr		The data to write.
		/// \param	[in]	bytes	The Size to write. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Write(const void * ptr, int bytes);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual int Read(void * ptr, Size bytes)
		///
		/// \brief	Reads from the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	ptr	The Pointer the data will stored in.
		/// \param	[in]	bytes		The Size to read. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual int Read(void * ptr, int bytes);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Seek(Offset offset, SeekOrigin origin)
		///
		/// \brief	Seeks within the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	offset	The offset. 
		/// \param	[in]	origin	The origin. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Seek(int offset, SeekOrigin origin);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Flush()
		///
		/// \brief	Flushes unsaved data.
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Flush();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual bool Eof() const
		///
		/// \brief	Returns true if the end of the stream is reached.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	True if end of stream is reached, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual bool Eof() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void * Map()
		///
		/// \brief	Maps the stream to the memory.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	Pointer to the data.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void * Map();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual void Unmap()
		///
		/// \brief	Unmaps the stream.
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual void Unmap();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsMapped() const
		///
		/// \brief	Returns true if the stream is currently mapped to memory.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	True if mapped to memory, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsMapped() const;






		URI							m_uri;
		AccessMode					m_accessMode;
		AccessPattern				m_accessPattern;
		MIME						m_mime;
		Threading::CriticalSection	m_critSec;
		bool						m_isOpen;
		bool						m_isMapped;

	protected:

	private:

	};

}

#endif // stream_h__